#include "ZipReader.h"
#include "Logger.h"
#include "UnitTest++.h"
#include "Util.h"
#include "CrcCalculator.h"
#include "TestUtils.h"

using namespace std;

const char* zipFileName = "resources/file.zip";


TEST(ShouldVerifyTheExistanceOfAFileHeaderSignature)
{
    int offset = 0;
    ZipReader* zipReader = new ZipReader(zipFileName);

    CHECK(zipReader->hasNextFileHeader(offset));

    delete zipReader;
}

TEST(ShouldntFindAFileHeaderGivenANonZipFile)
{
    const char* fileName = "resources/nonZip.zip";
    int offset = 0;
    ZipReader* zipReader = new ZipReader(fileName);

    CHECK(zipReader->hasNextFileHeader(offset) == 0);

    delete zipReader;
}

TEST(ShouldPopulateAFileHeaderStruct)
{

    const char* expectedFileName = "file1.txt";
    const char* expectedExtraField = "UT\t";
    const char* expectedContent = "hello what are you doing?\n";

    FileHeader* expectedFileHeader = new FileHeader();

    TestUtils::populateFileHeader(expectedFileHeader, 10, 0, 0, 37600, 17071, 3976057570, 26, 26, 9, 28,
            expectedFileName, expectedExtraField, expectedContent);

    ZipReader* reader = new ZipReader(zipFileName);
    FileHeader* actualFileHeader = reader->extractFileHeaderFields(0);

    CHECK(*actualFileHeader == *expectedFileHeader);

    delete reader;
    reader = 0;
    delete actualFileHeader;
    actualFileHeader = 0;
    delete expectedFileHeader;
    expectedFileHeader = 0;
}

TEST(ShouldFindNextFileHeader)
{

    int offset = 0;
    const char* filePath = "resources/twofiles2.zip";
    ZipReader* reader = new ZipReader(filePath);

    CHECK(reader->hasNextFileHeader(offset));

    FileHeader* firstFileHeader = reader->extractFileHeaderFields(offset);

    offset += firstFileHeader->calculateSize();

    CHECK(reader->hasNextFileHeader(offset));

    delete firstFileHeader;
    delete reader;

}

TEST(ShouldReadTheExpectedTwoFileHeaders)
{

    const char* filePath = "resources/twofiles2.zip";

    ZipReader* reader = new ZipReader(filePath);

    const char* expectedFirstFileName = "file4.txt";
    const char* expectedFirstExtraField = "UT\t";
    const char* expectedFirstContent = "ola\n";

    const char* expectedSecondFileName = "file3.txt";
    const char* expectedSecondExtraField = "UT\t";
    const char* expectedSecondContent = "ola k ase\n";

    FileHeader* expectedFirstFileHeader = new FileHeader();
    FileHeader* expectedSecondFileHeader = new FileHeader();

    TestUtils::populateFileHeader(expectedFirstFileHeader, 10, 0, 0, 31356, 17076, 2684336629, 4, 4, 9, 28,
            expectedFirstFileName, expectedFirstExtraField, expectedFirstContent);

    TestUtils::populateFileHeader(expectedSecondFileHeader, 10, 0, 0, 31338, 17076, 609041548, 10, 10, 9, 28,
            expectedSecondFileName, expectedSecondExtraField, expectedSecondContent);

    list<FileHeader*> actualFileHeaderList = reader->extractFileHeaders();

    bool resp = *expectedFirstFileHeader == *actualFileHeaderList.front();

    CHECK(resp);
    CHECK(*expectedSecondFileHeader == *actualFileHeaderList.back());

    cleanupList(actualFileHeaderList);
    delete reader;
    delete expectedFirstFileHeader;
    delete expectedSecondFileHeader;
}

TEST(ShouldReadTheExpectedThreeFileHeaders)
{

    const char* filePath = "resources/threefiles.zip";

    ZipReader* reader = new ZipReader(filePath);

    const char* expectedFirstFileName = "file4.txt";
    const char* expectedFirstExtraField = "UT\t";
    const char* expectedFirstContent = "ola\n";

    const char* expectedSecondFileName = "file3.txt";
    const char* expectedSecondExtraField = "UT\t";
    const char* expectedSecondContent = "ola k ase\n";

    const char* expectedThirdFileName = "file1.txt";
    const char* expectedThirdExtraField = "UT\t";
    const char* expectedThirdContent = "hello what are you doing?\n";

    FileHeader* expectedFirstFileHeader = new FileHeader();
    FileHeader* expectedSecondFileHeader = new FileHeader();
    FileHeader* expectedThirdFileHeader = new FileHeader();

    TestUtils::populateFileHeader(expectedFirstFileHeader, 10, 0, 0, 33554, 17076, 2684336629, 4, 4, 9, 28,
            expectedFirstFileName, expectedFirstExtraField, expectedFirstContent);

    TestUtils::populateFileHeader(expectedSecondFileHeader, 10, 0, 0, 33554, 17076, 609041548, 10, 10, 9, 28,
            expectedSecondFileName, expectedSecondExtraField, expectedSecondContent);

    TestUtils::populateFileHeader(expectedThirdFileHeader, 10, 0, 0, 29964, 17072, 3976057570, 26, 26, 9, 28,
            expectedThirdFileName, expectedThirdExtraField, expectedThirdContent);

    list<FileHeader*> expectedFileHeadersList;

    expectedFileHeadersList.push_back(expectedFirstFileHeader);
    expectedFileHeadersList.push_back(expectedSecondFileHeader);
    expectedFileHeadersList.push_back(expectedThirdFileHeader);

    list<FileHeader*> actualFileHeaderList = reader->extractFileHeaders();

    int foundHeaders = 0;

    for(list<FileHeader*>::iterator expected = expectedFileHeadersList.begin();
            expected != expectedFileHeadersList.end(); expected++)
    {
        FileHeader* expectedFileHeader = *expected;
        for(list<FileHeader*>::iterator actual = actualFileHeaderList.begin();
                actual != actualFileHeaderList.end(); actual++)
        {

            FileHeader* actualFileHeader = *actual;

            if(*expectedFileHeader == *actualFileHeader)
            {
                foundHeaders++;
                break;
            }
        }
    }

    CHECK(foundHeaders == 3);

    cleanupList<FileHeader>(expectedFileHeadersList);
    cleanupList<FileHeader>(actualFileHeaderList);

    delete reader;
}

